1

写了一个socket.io服务,实现了用户区分、公聊、私聊等。。。
码云地址https://gitee.com/liuoomei/so...

app.js

//app.js
var express = require('express')
var app = express();
var server = require('http').Server(app);
// var io = require('socket.io')(server);
var path = require('path');

app.use(express.static(path.join(__dirname, 'public')))
app.get('/', function(req, res){
  res.sendFile(path.join(__dirname, 'index.html'));
});

module.exports = app;

bin/www

#!/usr/bin/env node

/**
 * Module dependencies.
 */

let app = require('../app');
let debug = require('debug')('mysocket:server');
let http = require('http');
let _ = require('underscore');

/**
 * Get port from environment and store in Express.
 */
let userLs = []
let port = normalizePort(process.env.PORT || '3000');
app.set('port', port);

/**
 * Create HTTP server.
 */

let server = http.createServer(app);

/**
 * Listen on provided port, on all network interfaces.
 */

server.listen(port);

let io = require('socket.io')(server);
io.on('connection', function(socket){
    socket.on('login', function(userid){
        let obj = {
            userid,
            id: socket.id
        }
        userLs.push(obj)
        console.log(userid + '建立了链接');
        socket.emit('userLs',userLs)
        socket.emit('login',socket.id)
    });
    
    // 判断用户离线事件可以通过socket.io自带的disconnect事件完成,当一个用户断开连接,disconnect事件就会触发
    socket.on('disconnect', function(){
        let _user = _.where(userLs,{id:socket.id})
        console.log('_user',_user)
        console.log(socket.id + '中断了链接');
        userLs = userLs.filter(it =>{
            return _user.every(item =>{
                return it.id != item.id
            })
        })
        // do somethings
        console.log('del',userLs)
    });
      
    socket.on('message', function (data) {
        //服务端像所以也没发送数据
        let _user = _.where(userLs,{id:socket.id})
        io.sockets.emit('message', {id:_user[0].id,userid:_user[0].userid,message:data.message}); //给所有人(包括自己)发送消息
        // socket.broadcast.emit('message', data.message); //给所有人(不包括自己)发送消息
    });

    socket.on('sayTo', function (data) {
        let toMsg = data.message;
        let toId = data.id;
        
        // nodejs的underscore扩展中的findWhere方法,可以在对象集合中,通过对象的属性值找到该对象并返回。

        let _user = _.where(userLs,{id:toId})
        if(_user){
            let toSocket = _.findWhere(io.sockets.sockets, {id: toId});
            // 通过该连接对象(toSocket)与链接到这个对象的客户端进行单独通信
            socket.emit('message', {id:socket.id,message:toMsg}) //向建立该连接的客户端广播
            toSocket.emit('message', {id:socket.id,message:toMsg});
        }else{
            socket.emit('error','该用户不在线')
        }
        
        // socket.emit() :向建立该连接的客户端广播
        // socket.broadcast.emit() :向除去建立该连接的客户端的所有客户端广播
        // io.sockets.emit() : 向所有客户端广播,等同于上面两个的和
        
    });
});

server.on('error', onError);
server.on('listening', onListening);

/**
 * Normalize a port into a number, string, or false.
 */

function normalizePort(val) {
  let port = parseInt(val, 10);

  if (isNaN(port)) {
    // named pipe
    return val;
  }

  if (port >= 0) {
    // port number
    return port;
  }

  return false;
}

/**
 * Event listener for HTTP server "error" event.
 */

function onError(error) {
  if (error.syscall !== 'listen') {
    throw error;
  }

  let bind = typeof port === 'string'
    ? 'Pipe ' + port
    : 'Port ' + port;

  // handle specific listen errors with friendly messages
  switch (error.code) {
    case 'EACCES':
      console.error(bind + ' requires elevated privileges');
      process.exit(1);
      break;
    case 'EADDRINUSE':
      console.error(bind + ' is already in use');
      process.exit(1);
      break;
    default:
      throw error;
  }
}

/**
 * Event listener for HTTP server "listening" event.
 */

function onListening() {
  let addr = server.address();
  let bind = typeof addr === 'string'
    ? 'pipe ' + addr
    : 'port ' + addr.port;
  debug('Listening on ' + bind);
  console.log(`服务已启动,端口:${addr.port}`)
}

public/index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        .chat{
            width: 300px;
            height: 500px;
            text-align: center;
            margin: 0 auto;
            border: 1px solid #ccc;
        }
        .message{
            width: 100%;
            height: 460px;
        }
        #table{
            border: 1px solid
        }
    </style>
</head>
<body>
    <div class="chat">
        <select name="" id="select" onchange="console.log()">
            
        </select>
        <div class="message"></div>
        <div>我是<span id="_id"></span></div>
        <input id="text" type="text" placeholder="请输入聊天信息">
        <button onclick="chat()">发送信息</button>
    </div>
    <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>
    <!-- 这里socket不需要引用外部文件,node后台运行会自动生成可以引用的js文件 -->
    <!-- <script src="https://cdn.bootcss.com/socket.io/2.2.0/socket.io.js"></script> -->
    <script src="/socket.io/socket.io.js"></script>
    <!-- <script src="./javascripts/underscore.min.js"></script> -->
    <script>
        let message = document.getElementsByClassName('message')[0]
        let socket = io.connect('http://localhost:3000');
        //
        let userid = this.getUuid()
        let userLs = []

        socket.emit('login', userid);
        //从服务端接收数据
        socket.on('login',function (data) {
            document.getElementById("_id").innerHTML = data;
        })
        socket.on('message',function (data) {
            message.innerHTML += `${data.id}:${data.message}` + '<br>';
        })
        socket.on('sayTo',function (data) {
            message.innerHTML += `${data.id}:${data.message}` + '<br>';
        })
        socket.on('userLs',function (data) {
            console.log(data)
            $("#select").append(`<option value="">所有人</option>`)
            if(data.length > 0){
                for(let item of data){
                    $("#select").append(`<option value="${item.id}">${item.id}</option>`)
                }
            }
        })
        socket.on('error', function(msg) {
            //错误提示     
            alert(msg)     
        });
        function chat(){
            let text = document.getElementById('text').value
            if(!text){
                alert('不能发送空消息!')
                return
            }
            //向服务端发送数据
            if($('#select option:selected').val()){
                console.log($('#select option:selected').val())
                // return
                socket.emit('sayTo', {id:$('#select option:selected').val(),message:text});
            }else{
                socket.emit('message', {message:text});
            }
        }
        function getUuid () {
            function S4 () {
                return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1)
            }
            return (S4() + S4() + '-' + S4() + '-' + S4() + '-' + S4() + '-' + S4() + S4() + S4())
        }
    </script>
</body>
</html>

liuoomei
175 声望18 粉丝

走出舒适区,外面的风景格外迷人!